//! 配置结构体定义
//!
//! 定义 log4r 的配置数据结构，支持 serde 反序列化。
//!
//! ## 主要类型
//!
//! - [`Log4rConfig`] - 主配置结构体
//! - [`AppendersConfig`] - Appender 配置集合
//! - [`ConsoleConfig`] - 控制台输出配置
//! - [`FileConfig`] - 文件输出配置
//! - [`FormatConfig`] - 格式化配置
//! - [`AsyncConfig`] - 异步配置
//!
//! ## 示例
//!
//! ```rust
//! use log4r::config::{Log4rConfig, ConsoleTarget, TimeZone};
//! use log4r::Level;
//!
//! // 使用默认配置
//! let config = Log4rConfig::default();
//! assert_eq!(config.level, Level::Info);
//! assert_eq!(config.app_name, "log4r");
//! ```

use std::collections::HashMap;

use serde::de::{self, Deserializer};
use serde::Deserialize;

use crate::level::Level;

// ============================================================================
// 轮转周期枚举
// ============================================================================

/// 时间轮转周期
///
/// 指定日志文件按时间周期自动轮转的策略。
///
/// ## 示例
///
/// ```rust
/// use log4r::RotationPeriod;
///
/// let period = RotationPeriod::default();
/// assert_eq!(period, RotationPeriod::None);
///
/// // 每天轮转
/// let daily = RotationPeriod::Daily;
/// ```
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub enum RotationPeriod {
    /// 不启用时间轮转（默认）
    #[default]
    None,
    /// 每小时轮转
    Hourly,
    /// 每天轮转
    Daily,
    /// 每周轮转（ISO week，周一为起始日）
    Weekly,
}

impl<'de> Deserialize<'de> for RotationPeriod {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        let s = String::deserialize(deserializer)?;
        // 大小写不敏感解析
        match s.to_lowercase().as_str() {
            "none" => Ok(RotationPeriod::None),
            "hourly" => Ok(RotationPeriod::Hourly),
            "daily" => Ok(RotationPeriod::Daily),
            "weekly" => Ok(RotationPeriod::Weekly),
            _ => Err(de::Error::custom(format!(
                "无效的轮转周期: '{}', 有效值: none, hourly, daily, weekly",
                s
            ))),
        }
    }
}

// ============================================================================
// 背压策略枚举
// ============================================================================

/// 背压策略
///
/// 当异步队列满时的处理策略。
///
/// ## 示例
///
/// ```rust
/// use log4r::config::BackpressureStrategy;
///
/// let strategy = BackpressureStrategy::default();
/// assert_eq!(strategy, BackpressureStrategy::Block);
/// ```
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum BackpressureStrategy {
    /// 阻塞等待（默认）- 队列满时阻塞发送线程直到有空间
    #[default]
    Block,
    // v0.2 Growth 特性:
    // DropOldest - 丢弃最旧的日志，写入新日志
    // DropNewest - 丢弃当前日志，不写入
    // Wal - 写入 WAL 文件，后台重放
}

// ============================================================================
// 枚举类型
// ============================================================================

/// 控制台输出目标
///
/// 指定日志输出到标准输出还是标准错误。
///
/// ## 示例
///
/// ```rust
/// use log4r::config::ConsoleTarget;
///
/// let target = ConsoleTarget::default();
/// assert_eq!(target, ConsoleTarget::Stdout);
/// ```
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum ConsoleTarget {
    /// 标准输出 (stdout)
    #[default]
    Stdout,
    /// 标准错误 (stderr)
    Stderr,
}

/// 时区配置
///
/// 指定日志时间戳使用本地时区还是 UTC。
///
/// ## 示例
///
/// ```rust
/// use log4r::config::TimeZone;
///
/// let tz = TimeZone::default();
/// assert_eq!(tz, TimeZone::Local);
/// ```
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum TimeZone {
    /// 本地时区
    #[default]
    Local,
    /// UTC 时区
    Utc,
}

// ============================================================================
// 默认值函数
// ============================================================================

fn default_level() -> Level {
    Level::Info
}

fn default_app_name() -> String {
    "log4r".to_string()
}

fn default_true() -> bool {
    true
}

fn default_pattern() -> String {
    "{time} [{level}] {target}: {message}".to_string()
}

fn default_time_format() -> String {
    "[year]-[month]-[day] [hour]:[minute]:[second]".to_string()
}

fn default_queue_size() -> usize {
    10000
}

fn default_colored() -> bool {
    true
}

fn default_batch_size() -> usize {
    100
}

fn default_batch_timeout_ms() -> u64 {
    100
}

// ============================================================================
// 配置结构体
// ============================================================================

/// 控制台 Appender 配置
///
/// 配置控制台日志输出的行为。
///
/// ## 示例
///
/// ```rust
/// use log4r::config::{ConsoleConfig, ConsoleTarget};
///
/// let config = ConsoleConfig::default();
/// assert!(config.enabled);
/// assert_eq!(config.target, ConsoleTarget::Stdout);
/// assert!(config.level.is_none());
/// assert!(config.colored); // 默认启用彩色
/// ```
#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
pub struct ConsoleConfig {
    /// 是否启用控制台输出，默认 true
    #[serde(default = "default_true")]
    pub enabled: bool,

    /// 输出目标: stdout 或 stderr，默认 stdout
    #[serde(default)]
    pub target: ConsoleTarget,

    /// 控制台独立的日志级别过滤，None 表示使用全局级别
    #[serde(default)]
    pub level: Option<Level>,

    /// 是否启用彩色输出，默认 true（需要 color feature）
    #[serde(default = "default_colored")]
    pub colored: bool,
}

impl Default for ConsoleConfig {
    fn default() -> Self {
        Self {
            enabled: true,
            target: ConsoleTarget::default(),
            level: None,
            colored: true,
        }
    }
}

/// 文件 Appender 配置
///
/// 配置文件日志输出的行为。
///
/// ## 示例
///
/// ```rust
/// use log4r::config::FileConfig;
///
/// let config = FileConfig {
///     enabled: true,
///     path: "logs/app.log".to_string(),
///     level: None,
///     max_size: None, // 不启用轮转
///     rotation: None, // 不启用时间轮转
///     max_files: Some(7), // 保留最近 7 个轮转文件
/// };
/// assert!(config.enabled);
///
/// // 启用 10MB 轮转
/// let rotating_config = FileConfig {
///     enabled: true,
///     path: "logs/app.log".to_string(),
///     level: None,
///     max_size: Some("10MB".to_string()),
///     rotation: None,
///     max_files: Some(30), // 保留最近 30 个轮转文件
/// };
/// assert!(rotating_config.max_size.is_some());
/// ```
/// 默认 max_files 值（与架构决策 12 一致）
fn default_max_files() -> Option<u32> {
    Some(7)
}

#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
pub struct FileConfig {
    /// 是否启用文件输出，默认 true
    #[serde(default = "default_true")]
    pub enabled: bool,

    /// 日志文件路径
    pub path: String,

    /// 文件独立的日志级别过滤，None 表示使用全局级别
    #[serde(default)]
    pub level: Option<Level>,

    /// 文件轮转最大大小，格式: "10MB", "500KB", "1GB"
    /// None 表示不启用大小轮转
    #[serde(default)]
    pub max_size: Option<String>,

    /// 时间轮转周期: "none", "hourly", "daily", "weekly"
    /// None 表示不启用时间轮转
    #[serde(default)]
    pub rotation: Option<RotationPeriod>,

    /// 历史文件数量限制，默认 7（与架构决策 12 一致）
    /// 设置为 0 禁用清理（无限保留）
    #[serde(default = "default_max_files")]
    pub max_files: Option<u32>,
}

/// Appender 配置集合
///
/// 包含所有输出目标的配置。
///
/// ## 示例
///
/// ```rust
/// use log4r::config::AppendersConfig;
///
/// let config = AppendersConfig::default();
/// assert!(config.console.is_none());
/// assert!(config.file.is_none());
/// ```
#[derive(Debug, Clone, Default, PartialEq, Eq, Deserialize)]
pub struct AppendersConfig {
    /// 控制台输出配置
    #[serde(default)]
    pub console: Option<ConsoleConfig>,

    /// 文件输出配置
    #[serde(default)]
    pub file: Option<FileConfig>,
}

/// 格式化配置
///
/// 配置日志输出的格式。
///
/// ## 示例
///
/// ```rust
/// use log4r::config::{FormatConfig, TimeZone};
///
/// let config = FormatConfig::default();
/// assert_eq!(config.pattern, "{time} [{level}] {target}: {message}");
/// assert_eq!(config.time_zone, TimeZone::Local);
/// ```
#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
pub struct FormatConfig {
    /// 格式模板，默认 "{time} [{level}] {target}: {message}"
    #[serde(default = "default_pattern")]
    pub pattern: String,

    /// 时间格式，默认 `[year]-[month]-[day] [hour]:[minute]:[second]`
    #[serde(default = "default_time_format")]
    pub time_format: String,

    /// 时区配置，默认 local
    #[serde(default)]
    pub time_zone: TimeZone,
}

impl Default for FormatConfig {
    fn default() -> Self {
        Self {
            pattern: default_pattern(),
            time_format: default_time_format(),
            time_zone: TimeZone::default(),
        }
    }
}

/// 异步配置
///
/// 配置异步日志处理的行为。
///
/// ## 示例
///
/// ```rust
/// use log4r::config::AsyncConfig;
///
/// let config = AsyncConfig::default();
/// assert!(config.enabled);
/// assert_eq!(config.queue_size, 10000);
/// assert_eq!(config.backpressure, log4r::config::BackpressureStrategy::Block);
/// assert_eq!(config.batch_size, 100);
/// assert_eq!(config.batch_timeout_ms, 100);
/// ```
#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
pub struct AsyncConfig {
    /// 是否启用异步模式，默认 true
    #[serde(default = "default_true")]
    pub enabled: bool,

    /// 队列大小，默认 10000
    #[serde(default = "default_queue_size")]
    pub queue_size: usize,

    /// 背压策略，默认 Block
    #[serde(default)]
    pub backpressure: BackpressureStrategy,

    /// 批量处理大小，默认 100
    #[serde(default = "default_batch_size")]
    pub batch_size: usize,

    /// 批量超时时间（毫秒），默认 100
    #[serde(default = "default_batch_timeout_ms")]
    pub batch_timeout_ms: u64,
}

impl Default for AsyncConfig {
    fn default() -> Self {
        Self {
            enabled: true,
            queue_size: 10000,
            backpressure: BackpressureStrategy::default(),
            batch_size: 100,
            batch_timeout_ms: 100,
        }
    }
}

/// 队列大小最大值警告阈值
const MAX_QUEUE_SIZE_WARNING: usize = 1_000_000;

impl AsyncConfig {
    /// 验证配置值
    ///
    /// 检查配置参数是否有效：
    /// - `queue_size` 为 0 时返回 `ConfigError`
    /// - `queue_size` 大于 1000000 时输出 stderr 警告但仍返回 Ok
    /// - `batch_size` 为 0 时返回 `ConfigError`
    /// - `batch_timeout_ms` 为 0 时返回 `ConfigError`
    ///
    /// # Errors
    ///
    /// - `Log4rError::ConfigError` - queue_size、batch_size 或 batch_timeout_ms 为 0 时
    ///
    /// # Examples
    ///
    /// ```rust
    /// use log4r::config::AsyncConfig;
    ///
    /// // 有效配置（使用默认值）
    /// let config = AsyncConfig::default();
    /// assert!(config.validate().is_ok());
    /// ```
    pub fn validate(&self) -> Result<(), crate::error::Log4rError> {
        // AC-6.3.3: queue_size 为 0 时返回错误
        if self.queue_size == 0 {
            return Err(crate::error::Log4rError::config(
                "async.queue_size 不能为 0",
            ));
        }

        // AC-6.3.4: queue_size 过大时输出警告
        if self.queue_size > MAX_QUEUE_SIZE_WARNING {
            eprintln!(
                "[log4r] 警告: queue_size ({}) 过大，可能导致内存占用过高",
                self.queue_size
            );
        }

        // AC-14.4.4 #7: batch_size 为 0 时返回错误
        if self.batch_size == 0 {
            return Err(crate::error::Log4rError::config(
                "async.batch_size 不能为 0",
            ));
        }

        // AC-14.4.4 #8: batch_timeout_ms 为 0 时返回错误
        if self.batch_timeout_ms == 0 {
            return Err(crate::error::Log4rError::config(
                "async.batch_timeout_ms 不能为 0",
            ));
        }

        Ok(())
    }
}

/// log4r 主配置结构体
///
/// 包含所有日志配置选项。
///
/// ## 示例
///
/// ```rust
/// use log4r::config::Log4rConfig;
/// use log4r::Level;
///
/// let config = Log4rConfig::default();
/// assert_eq!(config.level, Level::Info);
/// assert_eq!(config.app_name, "log4r");
/// assert!(config.modules.is_empty());
/// ```
#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
pub struct Log4rConfig {
    /// 全局日志级别，默认 INFO
    #[serde(default = "default_level")]
    pub level: Level,

    /// 应用名称，用于系统日志标识，默认 "log4r"
    #[serde(default = "default_app_name")]
    pub app_name: String,

    /// 模块级别覆盖配置
    #[serde(default)]
    pub modules: HashMap<String, Level>,

    /// Appender 配置
    #[serde(default)]
    pub appenders: AppendersConfig,

    /// 格式化配置
    #[serde(default)]
    pub format: FormatConfig,

    /// 异步配置
    #[serde(default, rename = "async")]
    pub async_config: AsyncConfig,
}

impl Default for Log4rConfig {
    fn default() -> Self {
        Self {
            level: Level::Info,
            app_name: "log4r".to_string(),
            modules: HashMap::new(),
            appenders: AppendersConfig::default(),
            format: FormatConfig::default(),
            async_config: AsyncConfig::default(),
        }
    }
}

// ============================================================================
// 大小解析函数
// ============================================================================

/// 解析大小字符串，支持 B, KB, MB, GB 单位（大小写不敏感）
///
/// # Arguments
/// * `s` - 大小字符串，如 "10MB", "500KB", "1GB", "1024"
///
/// # Returns
/// * `Ok(u64)` - 解析后的字节数
/// * `Err(Log4rError::ConfigError)` - 解析失败或值为 0
///
/// # 示例
///
/// ```rust
/// use log4r::config::parse_size;
///
/// assert_eq!(parse_size("10MB").unwrap(), 10 * 1024 * 1024);
/// assert_eq!(parse_size("500KB").unwrap(), 500 * 1024);
/// assert_eq!(parse_size("1GB").unwrap(), 1024 * 1024 * 1024);
/// assert_eq!(parse_size("1024").unwrap(), 1024); // 无单位默认字节
/// assert!(parse_size("0").is_err());
/// assert!(parse_size("invalid").is_err());
/// ```
pub fn parse_size(s: &str) -> Result<u64, crate::error::Log4rError> {
    let s = s.trim();

    if s.is_empty() {
        return Err(crate::error::Log4rError::config("大小字符串不能为空"));
    }

    // 检查负数
    if s.starts_with('-') {
        return Err(crate::error::Log4rError::config("max_size 不能为负数"));
    }

    let s = s.to_uppercase();

    let (num_str, multiplier) = if s.ends_with("GB") {
        (&s[..s.len() - 2], 1024u64 * 1024 * 1024)
    } else if s.ends_with("MB") {
        (&s[..s.len() - 2], 1024u64 * 1024)
    } else if s.ends_with("KB") {
        (&s[..s.len() - 2], 1024u64)
    } else if s.ends_with('B') {
        (&s[..s.len() - 1], 1u64)
    } else {
        // 无单位默认字节
        (s.as_str(), 1u64)
    };

    let num: u64 = num_str
        .trim()
        .parse()
        .map_err(|_| crate::error::Log4rError::config(format!("无效的大小格式: {}", s)))?;

    if num == 0 {
        return Err(crate::error::Log4rError::config("max_size 不能为 0"));
    }

    Ok(num * multiplier)
}

#[cfg(test)]
#[allow(clippy::unwrap_used, clippy::expect_used, clippy::clone_on_copy)]
mod tests {
    use super::*;

    // AC-3.1.1, AC-3.1.8: Log4rConfig 默认值
    #[test]
    fn test_log4r_config_defaults() {
        let config = Log4rConfig::default();
        assert_eq!(config.level, Level::Info);
        assert_eq!(config.app_name, "log4r");
        assert!(config.modules.is_empty());
    }

    // AC-3.1.2: AppendersConfig 默认值
    #[test]
    fn test_appenders_config_defaults() {
        let config = AppendersConfig::default();
        assert!(config.console.is_none());
        assert!(config.file.is_none());
    }

    // AC-3.1.3: ConsoleConfig 默认值
    #[test]
    fn test_console_config_defaults() {
        let config = ConsoleConfig::default();
        assert!(config.enabled);
        assert_eq!(config.target, ConsoleTarget::Stdout);
        assert!(config.level.is_none());
        assert!(config.colored); // AC-9.2.2: 默认启用彩色
    }

    // =========================================================================
    // Story 9.2: 彩色开关配置测试
    // =========================================================================

    // UT-9.2-001: ConsoleConfig.colored 默认值为 true (AC-9.2.2)
    #[test]
    fn test_console_config_colored_default_true() {
        // GIVEN/WHEN: 创建默认 ConsoleConfig
        let config = ConsoleConfig::default();

        // THEN: colored 应为 true
        assert!(config.colored);
    }

    // UT-9.2-002: TOML 解析 colored = false (AC-9.2.1)
    #[test]
    fn test_console_config_colored_false_from_toml() {
        // GIVEN: 包含 colored = false 的 TOML
        let toml_str = r#"
enabled = true
target = "stdout"
colored = false
"#;

        // WHEN: 反序列化
        let config: ConsoleConfig = toml::from_str(toml_str).unwrap();

        // THEN: colored 应为 false
        assert!(!config.colored);
    }

    // UT-9.2-003: TOML 解析 colored = true (AC-9.2.1)
    #[test]
    fn test_console_config_colored_true_from_toml() {
        // GIVEN: 包含 colored = true 的 TOML
        let toml_str = r#"
enabled = true
target = "stdout"
colored = true
"#;

        // WHEN: 反序列化
        let config: ConsoleConfig = toml::from_str(toml_str).unwrap();

        // THEN: colored 应为 true
        assert!(config.colored);
    }

    // UT-9.2-004: TOML 省略 colored 时使用默认值 true (AC-9.2.2)
    #[test]
    fn test_console_config_colored_default_when_omitted() {
        // GIVEN: 不包含 colored 的 TOML
        let toml_str = r#"
enabled = true
target = "stdout"
"#;

        // WHEN: 反序列化
        let config: ConsoleConfig = toml::from_str(toml_str).unwrap();

        // THEN: colored 应使用默认值 true
        assert!(config.colored);
    }

    // UT-9.2-005: 完整 Log4rConfig TOML 解析 colored (AC-9.2.1)
    #[test]
    fn test_log4r_config_console_colored_nested() {
        // GIVEN: 完整的 Log4rConfig TOML
        let toml_str = r#"
level = "info"
app_name = "test_app"

[appenders.console]
enabled = true
target = "stdout"
colored = false
"#;

        // WHEN: 反序列化
        let config: Log4rConfig = toml::from_str(toml_str).unwrap();

        // THEN: appenders.console.colored 应为 false
        assert!(config.appenders.console.is_some());
        let console = config.appenders.console.unwrap();
        assert!(!console.colored);
    }

    // UT-9.2-006: default_colored 函数返回 true
    #[test]
    fn test_default_colored_function() {
        // GIVEN/WHEN: 调用 default_colored
        let result = default_colored();

        // THEN: 应返回 true
        assert!(result);
    }

    // AC-3.1.5: FormatConfig 默认值
    #[test]
    fn test_format_config_defaults() {
        let config = FormatConfig::default();
        assert_eq!(config.pattern, "{time} [{level}] {target}: {message}");
        assert_eq!(
            config.time_format,
            "[year]-[month]-[day] [hour]:[minute]:[second]"
        );
        assert_eq!(config.time_zone, TimeZone::Local);
    }

    // AC-3.1.6: AsyncConfig 默认值
    #[test]
    fn test_async_config_defaults() {
        let config = AsyncConfig::default();
        assert!(config.enabled);
        assert_eq!(config.queue_size, 10000);
    }

    // AC-3.1.9: Send + Sync 编译时验证
    #[test]
    fn test_config_send_sync() {
        fn assert_send_sync<T: Send + Sync>() {}
        assert_send_sync::<Log4rConfig>();
        assert_send_sync::<AppendersConfig>();
        assert_send_sync::<ConsoleConfig>();
        assert_send_sync::<FileConfig>();
        assert_send_sync::<FormatConfig>();
        assert_send_sync::<AsyncConfig>();
        assert_send_sync::<ConsoleTarget>();
        assert_send_sync::<TimeZone>();
    }

    // 枚举默认值测试
    #[test]
    fn test_console_target_default() {
        assert_eq!(ConsoleTarget::default(), ConsoleTarget::Stdout);
    }

    #[test]
    fn test_timezone_default() {
        assert_eq!(TimeZone::default(), TimeZone::Local);
    }

    // UT-3.1-010: 测试 default_queue_size 函数
    #[test]
    fn test_default_queue_size_value() {
        // GIVEN/WHEN: 调用 default_queue_size
        let size = default_queue_size();

        // THEN: 应返回 10000
        assert_eq!(size, 10000);
    }

    // UT-3.1-011: 测试 AsyncConfig 使用 default_queue_size
    #[test]
    fn test_async_config_uses_default_queue_size() {
        // GIVEN: 只包含 enabled 字段的 TOML
        let toml_str = r#"enabled = true"#;

        // WHEN: 反序列化
        let config: AsyncConfig = toml::from_str(toml_str).unwrap();

        // THEN: queue_size 应使用默认值 10000
        assert_eq!(config.queue_size, 10000);
        assert_eq!(config.queue_size, default_queue_size());
    }

    // UT-3.1-012: 测试所有默认值函数
    #[test]
    fn test_all_default_functions() {
        // 测试 default_level
        assert_eq!(default_level(), Level::Info);

        // 测试 default_app_name
        assert_eq!(default_app_name(), "log4r");

        // 测试 default_true
        assert!(default_true());

        // 测试 default_pattern
        assert_eq!(default_pattern(), "{time} [{level}] {target}: {message}");

        // 测试 default_time_format
        assert_eq!(
            default_time_format(),
            "[year]-[month]-[day] [hour]:[minute]:[second]"
        );

        // 测试 default_queue_size
        assert_eq!(default_queue_size(), 10000);
    }

    // =========================================================================
    // Story 6.3: 队列大小配置测试
    // =========================================================================

    // UT-6.3-001: TOML 解析自定义 queue_size (AC-6.3.1)
    #[test]
    fn test_async_config_custom_queue_size() {
        // GIVEN: 包含自定义 queue_size 的 TOML
        let toml_str = r#"
enabled = true
queue_size = 50000
"#;

        // WHEN: 反序列化
        let config: AsyncConfig = toml::from_str(toml_str).unwrap_or_default();

        // THEN: queue_size 应为 50000
        assert_eq!(config.queue_size, 50000);
        assert!(config.enabled);
    }

    // UT-6.3-002: 默认值 10000 (AC-6.3.2)
    #[test]
    fn test_async_config_default_queue_size() {
        // GIVEN: 空的 TOML 配置
        let toml_str = "";

        // WHEN: 反序列化
        let config: AsyncConfig = toml::from_str(toml_str).unwrap_or_default();

        // THEN: queue_size 应使用默认值 10000
        assert_eq!(config.queue_size, 10000);
    }

    // UT-6.3-003: queue_size = 0 返回错误 (AC-6.3.3)
    #[test]
    fn test_async_config_validate_zero_queue_size() {
        // GIVEN: queue_size 为 0 的配置
        let config = AsyncConfig {
            enabled: true,
            queue_size: 0,
            ..Default::default()
        };

        // WHEN: 验证配置
        let result = config.validate();

        // THEN: 应返回 ConfigError
        assert!(result.is_err());
        let err = result.unwrap_err();
        let err_msg = err.to_string();
        assert!(err_msg.contains("queue_size"));
        assert!(err_msg.contains("0"));
    }

    // UT-6.3-004: queue_size > 1000000 警告 (AC-6.3.4)
    #[test]
    fn test_async_config_validate_large_queue_size() {
        // GIVEN: queue_size 过大的配置
        let config = AsyncConfig {
            enabled: true,
            queue_size: 2_000_000,
            ..Default::default()
        };

        // WHEN: 验证配置
        let result = config.validate();

        // THEN: 应返回 Ok（警告输出到 stderr，不影响返回值）
        assert!(result.is_ok());
    }

    // UT-6.3-005: 边界值测试 - queue_size = 1 (AC-6.3.1)
    #[test]
    fn test_async_config_validate_min_valid_queue_size() {
        // GIVEN: queue_size 为最小有效值 1
        let config = AsyncConfig {
            enabled: true,
            queue_size: 1,
            ..Default::default()
        };

        // WHEN: 验证配置
        let result = config.validate();

        // THEN: 应返回 Ok
        assert!(result.is_ok());
    }

    // UT-6.3-006: 边界值测试 - queue_size = 1000000 (AC-6.3.1)
    #[test]
    fn test_async_config_validate_max_no_warning_queue_size() {
        // GIVEN: queue_size 为警告阈值
        let config = AsyncConfig {
            enabled: true,
            queue_size: 1_000_000,
            ..Default::default()
        };

        // WHEN: 验证配置
        let result = config.validate();

        // THEN: 应返回 Ok（刚好不触发警告）
        assert!(result.is_ok());
    }

    // UT-6.3-007: 边界值测试 - queue_size = 1000001 (AC-6.3.4)
    #[test]
    fn test_async_config_validate_just_over_warning_threshold() {
        // GIVEN: queue_size 刚好超过警告阈值
        let config = AsyncConfig {
            enabled: true,
            queue_size: 1_000_001,
            ..Default::default()
        };

        // WHEN: 验证配置
        let result = config.validate();

        // THEN: 应返回 Ok（触发警告但仍成功）
        assert!(result.is_ok());
    }

    // UT-6.3-008: 验证 AsyncConfig 在 Log4rConfig 中正确嵌套 (AC-6.3.1)
    #[test]
    fn test_log4r_config_async_nested() {
        // GIVEN: 完整的 Log4rConfig TOML
        let toml_str = r#"
level = "info"
app_name = "test_app"

[async]
enabled = true
queue_size = 50000
"#;

        // WHEN: 反序列化
        let config: Log4rConfig = toml::from_str(toml_str).unwrap_or_default();

        // THEN: async_config 应正确解析
        assert_eq!(config.async_config.queue_size, 50000);
        assert!(config.async_config.enabled);
    }

    // UT-6.3-009: 有效配置验证通过
    #[test]
    fn test_async_config_validate_valid() {
        // GIVEN: 有效的默认配置
        let config = AsyncConfig::default();

        // WHEN: 验证配置
        let result = config.validate();

        // THEN: 应返回 Ok
        assert!(result.is_ok());
    }

    // =========================================================================
    // Story 6.4: 背压策略测试
    // =========================================================================

    // UT-6.4-001: BackpressureStrategy 默认值为 Block (AC-6.4.4)
    #[test]
    fn test_backpressure_strategy_default() {
        // GIVEN/WHEN: 获取默认值
        let strategy = BackpressureStrategy::default();

        // THEN: 应为 Block
        assert_eq!(strategy, BackpressureStrategy::Block);
    }

    // UT-6.4-002: TOML 解析 backpressure = "block" (AC-6.4.4)
    #[test]
    fn test_backpressure_strategy_toml_parse() {
        // GIVEN: 包含 backpressure 的 TOML
        let toml_str = r#"
enabled = true
queue_size = 10000
backpressure = "block"
"#;

        // WHEN: 反序列化
        let config: AsyncConfig = toml::from_str(toml_str).unwrap_or_default();

        // THEN: backpressure 应为 Block
        assert_eq!(config.backpressure, BackpressureStrategy::Block);
    }

    // UT-6.4-003: AsyncConfig 默认包含 backpressure = Block (AC-6.4.4)
    #[test]
    fn test_async_config_default_backpressure() {
        // GIVEN/WHEN: 创建默认 AsyncConfig
        let config = AsyncConfig::default();

        // THEN: backpressure 应为 Block
        assert_eq!(config.backpressure, BackpressureStrategy::Block);
    }

    // UT-6.4-004: TOML 省略 backpressure 时使用默认值 (AC-6.4.4)
    #[test]
    fn test_async_config_missing_backpressure_uses_default() {
        // GIVEN: 不包含 backpressure 的 TOML
        let toml_str = r#"
enabled = true
queue_size = 5000
"#;

        // WHEN: 反序列化
        let config: AsyncConfig = toml::from_str(toml_str).unwrap_or_default();

        // THEN: backpressure 应使用默认值 Block
        assert_eq!(config.backpressure, BackpressureStrategy::Block);
    }

    // UT-6.4-005: Log4rConfig 完整 TOML 解析 backpressure (AC-6.4.4)
    #[test]
    fn test_log4r_config_backpressure_nested() {
        // GIVEN: 完整的 Log4rConfig TOML
        let toml_str = r#"
level = "info"
app_name = "test_app"

[async]
enabled = true
queue_size = 10000
backpressure = "block"
"#;

        // WHEN: 反序列化
        let config: Log4rConfig = toml::from_str(toml_str).unwrap_or_default();

        // THEN: async_config.backpressure 应正确解析
        assert_eq!(
            config.async_config.backpressure,
            BackpressureStrategy::Block
        );
    }

    // UT-6.4-006: BackpressureStrategy 实现 Send + Sync
    #[test]
    fn test_backpressure_strategy_send_sync() {
        fn assert_send_sync<T: Send + Sync>() {}
        assert_send_sync::<BackpressureStrategy>();
    }

    // UT-6.4-007: BackpressureStrategy 实现 Clone, Copy, PartialEq, Eq
    #[test]
    fn test_backpressure_strategy_traits() {
        let s1 = BackpressureStrategy::Block;
        let s2 = s1; // Copy
        let s3 = s1.clone(); // Clone

        assert_eq!(s1, s2); // PartialEq
        assert_eq!(s2, s3);
    }

    // =========================================================================
    // Story 14.4: 批量配置测试
    // =========================================================================

    // UT-14.4-001: 测试 TOML 解析 batch_size (AC-14.4.1 #1)
    #[test]
    fn test_async_config_batch_size_from_toml() {
        // GIVEN: 包含 batch_size 的 TOML
        let toml_str = r#"
enabled = true
batch_size = 50
"#;

        // WHEN: 反序列化
        let config: AsyncConfig = toml::from_str(toml_str).unwrap();

        // THEN: batch_size 应为 50
        assert_eq!(config.batch_size, 50);
    }

    // UT-14.4-002: 测试 TOML 解析 batch_timeout_ms (AC-14.4.2 #3)
    #[test]
    fn test_async_config_batch_timeout_ms_from_toml() {
        // GIVEN: 包含 batch_timeout_ms 的 TOML
        let toml_str = r#"
enabled = true
batch_timeout_ms = 200
"#;

        // WHEN: 反序列化
        let config: AsyncConfig = toml::from_str(toml_str).unwrap();

        // THEN: batch_timeout_ms 应为 200
        assert_eq!(config.batch_timeout_ms, 200);
    }

    // UT-14.4-003: 测试默认值 batch_size = 100, batch_timeout_ms = 100 (AC-14.4.1 #2, AC-14.4.2 #4)
    #[test]
    fn test_async_config_batch_defaults() {
        // GIVEN/WHEN: 创建默认 AsyncConfig
        let config = AsyncConfig::default();

        // THEN: 默认值应正确
        assert_eq!(config.batch_size, 100);
        assert_eq!(config.batch_timeout_ms, 100);
    }

    // UT-14.4-004: 测试 batch_size = 0 验证失败 (AC-14.4.4 #7)
    #[test]
    fn test_async_config_validate_zero_batch_size() {
        // GIVEN: batch_size 为 0 的配置
        let config = AsyncConfig {
            batch_size: 0,
            ..Default::default()
        };

        // WHEN: 验证配置
        let result = config.validate();

        // THEN: 应返回 ConfigError，错误信息包含 "batch_size"
        assert!(result.is_err());
        let err = result.unwrap_err();
        let err_msg = err.to_string();
        assert!(err_msg.contains("batch_size"));
    }

    // UT-14.4-005: 测试 batch_timeout_ms = 0 验证失败 (AC-14.4.4 #8)
    #[test]
    fn test_async_config_validate_zero_batch_timeout_ms() {
        // GIVEN: batch_timeout_ms 为 0 的配置
        let config = AsyncConfig {
            batch_timeout_ms: 0,
            ..Default::default()
        };

        // WHEN: 验证配置
        let result = config.validate();

        // THEN: 应返回 ConfigError，错误信息包含 "batch_timeout_ms"
        assert!(result.is_err());
        let err = result.unwrap_err();
        let err_msg = err.to_string();
        assert!(err_msg.contains("batch_timeout_ms"));
    }

    // UT-14.4-006: 测试 TOML 省略 batch_size 时使用默认值 (AC-14.4.1 #2)
    #[test]
    fn test_async_config_batch_size_default_when_omitted() {
        // GIVEN: 不包含 batch_size 的 TOML
        let toml_str = r#"
enabled = true
queue_size = 5000
"#;

        // WHEN: 反序列化
        let config: AsyncConfig = toml::from_str(toml_str).unwrap();

        // THEN: batch_size 应使用默认值 100
        assert_eq!(config.batch_size, 100);
    }

    // UT-14.4-007: 测试 TOML 省略 batch_timeout_ms 时使用默认值 (AC-14.4.2 #4)
    #[test]
    fn test_async_config_batch_timeout_ms_default_when_omitted() {
        // GIVEN: 不包含 batch_timeout_ms 的 TOML
        let toml_str = r#"
enabled = true
queue_size = 5000
"#;

        // WHEN: 反序列化
        let config: AsyncConfig = toml::from_str(toml_str).unwrap();

        // THEN: batch_timeout_ms 应使用默认值 100
        assert_eq!(config.batch_timeout_ms, 100);
    }

    // UT-14.4-008: 测试完整 Log4rConfig TOML 解析批量参数 (AC-14.4.1, AC-14.4.2)
    #[test]
    fn test_log4r_config_batch_params_nested() {
        // GIVEN: 完整的 Log4rConfig TOML
        let toml_str = r#"
level = "info"
app_name = "test_app"

[async]
enabled = true
queue_size = 10000
batch_size = 50
batch_timeout_ms = 200
"#;

        // WHEN: 反序列化
        let config: Log4rConfig = toml::from_str(toml_str).unwrap();

        // THEN: 批量参数应正确解析
        assert_eq!(config.async_config.batch_size, 50);
        assert_eq!(config.async_config.batch_timeout_ms, 200);
    }

    // UT-14.4-009: 测试 default_batch_size 函数
    #[test]
    fn test_default_batch_size_function() {
        // GIVEN/WHEN: 调用 default_batch_size
        let result = default_batch_size();

        // THEN: 应返回 100
        assert_eq!(result, 100);
    }

    // UT-14.4-010: 测试 default_batch_timeout_ms 函数
    #[test]
    fn test_default_batch_timeout_ms_function() {
        // GIVEN/WHEN: 调用 default_batch_timeout_ms
        let result = default_batch_timeout_ms();

        // THEN: 应返回 100
        assert_eq!(result, 100);
    }

    // UT-14.4-011: 测试有效批量配置验证通过
    #[test]
    fn test_async_config_validate_valid_batch_params() {
        // GIVEN: 有效的批量配置
        let config = AsyncConfig {
            batch_size: 50,
            batch_timeout_ms: 200,
            ..Default::default()
        };

        // WHEN: 验证配置
        let result = config.validate();

        // THEN: 应返回 Ok
        assert!(result.is_ok());
    }

    // UT-14.4-012: 测试边界值 batch_size = 1
    #[test]
    fn test_async_config_validate_min_valid_batch_size() {
        // GIVEN: batch_size 为最小有效值 1
        let config = AsyncConfig {
            batch_size: 1,
            ..Default::default()
        };

        // WHEN: 验证配置
        let result = config.validate();

        // THEN: 应返回 Ok
        assert!(result.is_ok());
    }

    // UT-14.4-013: 测试边界值 batch_timeout_ms = 1
    #[test]
    fn test_async_config_validate_min_valid_batch_timeout_ms() {
        // GIVEN: batch_timeout_ms 为最小有效值 1
        let config = AsyncConfig {
            batch_timeout_ms: 1,
            ..Default::default()
        };

        // WHEN: 验证配置
        let result = config.validate();

        // THEN: 应返回 Ok
        assert!(result.is_ok());
    }

    // =========================================================================
    // Story 10.1: parse_size 函数测试
    // =========================================================================

    // UT-10.1-001: parse_size("10MB") = 10485760 (AC-10.1.5 #8)
    #[test]
    fn test_parse_size_mb() {
        // GIVEN: "10MB"
        // WHEN: 解析
        let result = parse_size("10MB");

        // THEN: 应返回 10 * 1024 * 1024
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), 10 * 1024 * 1024);
    }

    // UT-10.1-002: parse_size("500KB") = 512000 (AC-10.1.5 #9)
    #[test]
    fn test_parse_size_kb() {
        // GIVEN: "500KB"
        // WHEN: 解析
        let result = parse_size("500KB");

        // THEN: 应返回 500 * 1024
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), 500 * 1024);
    }

    // UT-10.1-003: parse_size("1GB") = 1073741824 (AC-10.1.5 #10)
    #[test]
    fn test_parse_size_gb() {
        // GIVEN: "1GB"
        // WHEN: 解析
        let result = parse_size("1GB");

        // THEN: 应返回 1 * 1024 * 1024 * 1024
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), 1024 * 1024 * 1024);
    }

    // UT-10.1-004: parse_size("1024") = 1024 (无单位默认字节)
    #[test]
    fn test_parse_size_no_unit() {
        // GIVEN: "1024"
        // WHEN: 解析
        let result = parse_size("1024");

        // THEN: 应返回 1024
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), 1024);
    }

    // UT-10.1-005: parse_size("0") 返回错误 (AC-10.1.7 #12)
    #[test]
    fn test_parse_size_zero_returns_error() {
        // GIVEN: "0"
        // WHEN: 解析
        let result = parse_size("0");

        // THEN: 应返回错误
        assert!(result.is_err());
        let err = result.unwrap_err();
        assert!(err.to_string().contains("0"));
    }

    // UT-10.1-006: parse_size("invalid") 返回错误 (AC-10.1.7 #13)
    #[test]
    fn test_parse_size_invalid_returns_error() {
        // GIVEN: "invalid"
        // WHEN: 解析
        let result = parse_size("invalid");

        // THEN: 应返回错误
        assert!(result.is_err());
    }

    // UT-10.1-007: parse_size 大小写不敏感
    #[test]
    fn test_parse_size_case_insensitive() {
        // GIVEN: 各种大小写组合
        // WHEN: 解析
        // THEN: 都应成功
        assert_eq!(parse_size("10mb").unwrap(), 10 * 1024 * 1024);
        assert_eq!(parse_size("10Mb").unwrap(), 10 * 1024 * 1024);
        assert_eq!(parse_size("10mB").unwrap(), 10 * 1024 * 1024);
        assert_eq!(parse_size("500kb").unwrap(), 500 * 1024);
        assert_eq!(parse_size("1gb").unwrap(), 1024 * 1024 * 1024);
    }

    // UT-10.1-008: parse_size 支持 B 单位
    #[test]
    fn test_parse_size_bytes() {
        // GIVEN: "100B"
        // WHEN: 解析
        let result = parse_size("100B");

        // THEN: 应返回 100
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), 100);
    }

    // UT-10.1-009: parse_size 处理空格
    #[test]
    fn test_parse_size_with_whitespace() {
        // GIVEN: 带空格的字符串
        // WHEN: 解析
        // THEN: 应正确处理
        assert_eq!(parse_size("  10MB  ").unwrap(), 10 * 1024 * 1024);
        assert_eq!(parse_size("10 MB").unwrap(), 10 * 1024 * 1024);
    }

    // UT-10.1-010: parse_size 空字符串返回错误
    #[test]
    fn test_parse_size_empty_returns_error() {
        // GIVEN: 空字符串
        // WHEN: 解析
        let result = parse_size("");

        // THEN: 应返回错误
        assert!(result.is_err());
    }

    // UT-10.1-011: parse_size 负数返回错误 (AC-10.1.7)
    #[test]
    fn test_parse_size_negative_returns_error() {
        // GIVEN: 负数字符串
        // WHEN: 解析
        let result = parse_size("-10MB");

        // THEN: 应返回错误，错误信息包含 "负数"
        assert!(result.is_err());
        let err = result.unwrap_err();
        let err_msg = err.to_string();
        assert!(err_msg.contains("负数"));
    }

    // UT-10.1-011: FileConfig.max_size 字段测试
    #[test]
    fn test_file_config_max_size_field() {
        // GIVEN: 包含 max_size 的 TOML
        let toml_str = r#"
enabled = true
path = "logs/app.log"
max_size = "10MB"
"#;

        // WHEN: 反序列化
        let config: FileConfig = toml::from_str(toml_str).unwrap();

        // THEN: max_size 应正确解析
        assert_eq!(config.max_size, Some("10MB".to_string()));
    }

    // UT-10.1-012: FileConfig.max_size 默认为 None
    #[test]
    fn test_file_config_max_size_default_none() {
        // GIVEN: 不包含 max_size 的 TOML
        let toml_str = r#"
enabled = true
path = "logs/app.log"
"#;

        // WHEN: 反序列化
        let config: FileConfig = toml::from_str(toml_str).unwrap();

        // THEN: max_size 应为 None
        assert!(config.max_size.is_none());
    }

    // =========================================================================
    // Story 10.2: RotationPeriod 枚举测试
    // =========================================================================

    // UT-10.2-001: RotationPeriod::Daily 解析 (AC-10.2.2 #5)
    #[test]
    fn test_rotation_period_daily_parse() {
        // GIVEN: "daily" 字符串
        let toml_str = r#"rotation = "daily""#;

        // WHEN: 反序列化
        #[allow(dead_code)]
        #[derive(Deserialize)]
        struct TestConfig {
            rotation: RotationPeriod,
        }
        let config: TestConfig = toml::from_str(toml_str).unwrap();

        // THEN: 应为 Daily
        assert_eq!(config.rotation, RotationPeriod::Daily);
    }

    // UT-10.2-002: RotationPeriod::Hourly 解析 (AC-10.2.2 #5)
    #[test]
    fn test_rotation_period_hourly_parse() {
        // GIVEN: "hourly" 字符串
        let toml_str = r#"rotation = "hourly""#;

        // WHEN: 反序列化
        #[allow(dead_code)]
        #[derive(Deserialize)]
        struct TestConfig {
            rotation: RotationPeriod,
        }
        let config: TestConfig = toml::from_str(toml_str).unwrap();

        // THEN: 应为 Hourly
        assert_eq!(config.rotation, RotationPeriod::Hourly);
    }

    // UT-10.2-003: RotationPeriod::Weekly 解析 (AC-10.2.2 #5)
    #[test]
    fn test_rotation_period_weekly_parse() {
        // GIVEN: "weekly" 字符串
        let toml_str = r#"rotation = "weekly""#;

        // WHEN: 反序列化
        #[allow(dead_code)]
        #[derive(Deserialize)]
        struct TestConfig {
            rotation: RotationPeriod,
        }
        let config: TestConfig = toml::from_str(toml_str).unwrap();

        // THEN: 应为 Weekly
        assert_eq!(config.rotation, RotationPeriod::Weekly);
    }

    // UT-10.2-004: RotationPeriod::None 解析 (AC-10.2.5 #14)
    #[test]
    fn test_rotation_period_none_parse() {
        // GIVEN: "none" 字符串
        let toml_str = r#"rotation = "none""#;

        // WHEN: 反序列化
        #[allow(dead_code)]
        #[derive(Deserialize)]
        struct TestConfig {
            rotation: RotationPeriod,
        }
        let config: TestConfig = toml::from_str(toml_str).unwrap();

        // THEN: 应为 None
        assert_eq!(config.rotation, RotationPeriod::None);
    }

    // UT-10.2-005: 大小写不敏感解析 (AC-10.2.2 #6)
    #[test]
    fn test_rotation_period_case_insensitive() {
        // GIVEN: 各种大小写组合
        #[allow(dead_code)]
        #[derive(Deserialize)]
        struct TestConfig {
            rotation: RotationPeriod,
        }

        // WHEN/THEN: 大写应正确解析
        let config: TestConfig = toml::from_str(r#"rotation = "HOURLY""#).unwrap();
        assert_eq!(config.rotation, RotationPeriod::Hourly);

        let config: TestConfig = toml::from_str(r#"rotation = "DAILY""#).unwrap();
        assert_eq!(config.rotation, RotationPeriod::Daily);

        let config: TestConfig = toml::from_str(r#"rotation = "WEEKLY""#).unwrap();
        assert_eq!(config.rotation, RotationPeriod::Weekly);

        // 混合大小写
        let config: TestConfig = toml::from_str(r#"rotation = "Daily""#).unwrap();
        assert_eq!(config.rotation, RotationPeriod::Daily);

        let config: TestConfig = toml::from_str(r#"rotation = "HoUrLy""#).unwrap();
        assert_eq!(config.rotation, RotationPeriod::Hourly);
    }

    // UT-10.2-006: 无效值返回错误 (AC-10.2.6 #15)
    #[test]
    fn test_rotation_period_invalid_returns_error() {
        // GIVEN: 无效的轮转周期
        #[allow(dead_code)]
        #[derive(Deserialize)]
        struct TestConfig {
            rotation: RotationPeriod,
        }

        // WHEN: 反序列化
        let result: Result<TestConfig, _> = toml::from_str(r#"rotation = "invalid""#);

        // THEN: 应返回错误
        assert!(result.is_err());
    }

    // UT-10.2-015: RotationPeriod 默认值为 None (AC-10.2.5 #13)
    #[test]
    fn test_rotation_period_default_none() {
        // GIVEN/WHEN: 获取默认值
        let period = RotationPeriod::default();

        // THEN: 应为 None
        assert_eq!(period, RotationPeriod::None);
    }

    // UT-10.2-016: RotationPeriod 实现 Send + Sync
    #[test]
    fn test_rotation_period_send_sync() {
        fn assert_send_sync<T: Send + Sync>() {}
        assert_send_sync::<RotationPeriod>();
    }

    // UT-10.2-017: RotationPeriod 实现 Clone, Copy, PartialEq, Eq
    #[test]
    fn test_rotation_period_traits() {
        let p1 = RotationPeriod::Daily;
        let p2 = p1; // Copy
        let p3 = p1.clone(); // Clone

        assert_eq!(p1, p2); // PartialEq
        assert_eq!(p2, p3);
    }

    // UT-10.2-018: FileConfig.rotation 字段测试
    #[test]
    fn test_file_config_rotation_field() {
        // GIVEN: 包含 rotation 的 TOML
        let toml_str = r#"
enabled = true
path = "logs/app.log"
rotation = "daily"
"#;

        // WHEN: 反序列化
        let config: FileConfig = toml::from_str(toml_str).unwrap();

        // THEN: rotation 应正确解析
        assert_eq!(config.rotation, Some(RotationPeriod::Daily));
    }

    // UT-10.2-019: FileConfig.rotation 默认为 None
    #[test]
    fn test_file_config_rotation_default_none() {
        // GIVEN: 不包含 rotation 的 TOML
        let toml_str = r#"
enabled = true
path = "logs/app.log"
"#;

        // WHEN: 反序列化
        let config: FileConfig = toml::from_str(toml_str).unwrap();

        // THEN: rotation 应为 None
        assert!(config.rotation.is_none());
    }

    // UT-10.2-020: FileConfig 同时包含 max_size 和 rotation
    #[test]
    fn test_file_config_max_size_and_rotation() {
        // GIVEN: 同时包含 max_size 和 rotation 的 TOML
        let toml_str = r#"
enabled = true
path = "logs/app.log"
max_size = "10MB"
rotation = "daily"
"#;

        // WHEN: 反序列化
        let config: FileConfig = toml::from_str(toml_str).unwrap();

        // THEN: 两个字段都应正确解析
        assert_eq!(config.max_size, Some("10MB".to_string()));
        assert_eq!(config.rotation, Some(RotationPeriod::Daily));
    }

    // UT-10.2-021: Log4rConfig 完整 TOML 解析 rotation
    #[test]
    fn test_log4r_config_file_rotation_nested() {
        // GIVEN: 完整的 Log4rConfig TOML
        let toml_str = r#"
level = "info"
app_name = "test_app"

[appenders.file]
enabled = true
path = "logs/app.log"
rotation = "hourly"
"#;

        // WHEN: 反序列化
        let config: Log4rConfig = toml::from_str(toml_str).unwrap();

        // THEN: appenders.file.rotation 应正确解析
        assert!(config.appenders.file.is_some());
        let file = config.appenders.file.unwrap();
        assert_eq!(file.rotation, Some(RotationPeriod::Hourly));
    }

    // =========================================================================
    // Story 10.3: 历史文件数量限制配置测试
    // =========================================================================

    // UT-10.3-012: FileConfig.max_files 字段测试 (AC-10.3.4 #11)
    #[test]
    fn test_file_config_max_files_field() {
        // GIVEN: 包含 max_files 的 TOML
        let toml_str = r#"
enabled = true
path = "logs/app.log"
max_files = 30
"#;

        // WHEN: 反序列化
        let config: FileConfig = toml::from_str(toml_str).unwrap();

        // THEN: max_files 应正确解析
        assert_eq!(config.max_files, Some(30));
    }

    // UT-10.3-013: FileConfig.max_files 默认值为 7 (AC-10.3.4 #10)
    #[test]
    fn test_file_config_max_files_default_seven() {
        // GIVEN: 不包含 max_files 的 TOML
        let toml_str = r#"
enabled = true
path = "logs/app.log"
"#;

        // WHEN: 反序列化
        let config: FileConfig = toml::from_str(toml_str).unwrap();

        // THEN: max_files 应使用默认值 7
        assert_eq!(config.max_files, Some(7));
    }

    // UT-10.3-014: FileConfig.max_files = 0 禁用清理 (AC-10.3.1 #3)
    #[test]
    fn test_file_config_max_files_zero_disables_cleanup() {
        // GIVEN: max_files = 0 的 TOML
        let toml_str = r#"
enabled = true
path = "logs/app.log"
max_files = 0
"#;

        // WHEN: 反序列化
        let config: FileConfig = toml::from_str(toml_str).unwrap();

        // THEN: max_files 应为 0
        assert_eq!(config.max_files, Some(0));
    }

    // UT-10.3-015: FileConfig 完整配置（max_size + rotation + max_files）(AC-10.3.8 #19)
    #[test]
    fn test_file_config_full_rotation_config() {
        // GIVEN: 完整轮转配置的 TOML
        let toml_str = r#"
enabled = true
path = "logs/app.log"
max_size = "10MB"
rotation = "daily"
max_files = 30
"#;

        // WHEN: 反序列化
        let config: FileConfig = toml::from_str(toml_str).unwrap();

        // THEN: 所有字段应正确解析
        assert_eq!(config.max_size, Some("10MB".to_string()));
        assert_eq!(config.rotation, Some(RotationPeriod::Daily));
        assert_eq!(config.max_files, Some(30));
    }

    // UT-10.3-016: Log4rConfig 完整 TOML 解析 max_files
    #[test]
    fn test_log4r_config_file_max_files_nested() {
        // GIVEN: 完整的 Log4rConfig TOML
        let toml_str = r#"
level = "info"
app_name = "test_app"

[appenders.file]
enabled = true
path = "logs/app.log"
rotation = "daily"
max_files = 14
"#;

        // WHEN: 反序列化
        let config: Log4rConfig = toml::from_str(toml_str).unwrap();

        // THEN: appenders.file.max_files 应正确解析
        assert!(config.appenders.file.is_some());
        let file = config.appenders.file.unwrap();
        assert_eq!(file.max_files, Some(14));
    }

    // UT-10.3-017: default_max_files 函数返回 Some(7)
    #[test]
    fn test_default_max_files_function() {
        // GIVEN/WHEN: 调用 default_max_files
        let result = default_max_files();

        // THEN: 应返回 Some(7)
        assert_eq!(result, Some(7));
    }
}
